<?php

namespace App\Trip\Orders\BookOrders\OrderChange;

use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Trip\Orders\Traits\OfflineOrderChangeOrRefundTimeValidTrait;
use App\Trip\Orders\Traits\ThrowErrorMessageTrait;
use App\Trip\Orders\TripOrderState;
use App\Trip\Train\TrainInfo\TrainInfo;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Validator;

class TrainOrderChange implements OrderChange
{
    use ThrowErrorMessageTrait, OfflineOrderChangeOrRefundTimeValidTrait;

    private TrainOrder     $order_info;
    private array          $passengers;
    private TrainInfo|null $train                 = null;
    private bool           $ignore_worktime_error = false;
    private bool           $has_other_error       = false;

    /**
     * @throws Exception
     */
    public function __construct(TrainOrder $order, array $passengers)
    {
        $this->order_info = $order;
        $this->setPassengers($passengers);
    }

    /**
     * @throws Exception
     */
    public function setPassengers(array $passengers): static
    {
        $validator = Validator::make($passengers, [
            '*.passenger_id' => "required",
            "*.sequence"     => "required",
        ]);
        if ($validator->fails()) {
            $this->throwOtherErrorMsg('参数错误');
        }
        $this->passengers = $passengers;
        return $this;
    }

    public function setTrain(TrainInfo $train_info): static
    {
        $this->train = $train_info;
        return $this;
    }

    public function canChangeToShow(): bool
    {
        return $this->setIgnoreWorkTimeError()->canChange();
    }

    public function canChange(): bool
    {
        try {
            $this->validTime();
            $this->validOrder();
            $this->validateTrainInfo();
            $this->validatePassengers();
            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * @throws Exception
     */
    private function validOrder(): void
    {
        if ($this->order_info->isCancel()) {
            $this->throwErrorMessage("订单已取消");
        }
        if ($this->order_info->isChangeNew()) {
            $this->throwOtherErrorMsg("该订单为改签订单，无法继续改签");
        }

        if ($this->order_info->isChanging()) {
            $this->throwOtherErrorMsg("该订单正在改签");
        }

        if (!in_array($this->order_info->getOrderState(), [
            TripOrderState::ORDER_STATE_TICKETED,
            TripOrderState::ORDER_STATE_CHANGE_FAILED,
            TripOrderState::ORDER_STATE_CHANGED,
        ])) {
            $this->throwOtherErrorMsg("当前订单状态无法改签");
        }
    }

    /**
     * @throws Exception
     */
    public function validateTrainInfo(): void
    {
        $order_train_info = $this->order_info->getTrainInfo();
        $train_date       = $order_train_info->getTrainDate();
        if (Carbon::parse($train_date)->lessThan(Carbon::today())) {
            $this->throwOtherErrorMsg("暂无可改签车次");
        }

        // 验证原订单 是否超过当天
        if (Carbon::today()->greaterThan(Carbon::parse($order_train_info->getTrainDate()))) {
            $this->throwOtherErrorMsg("暂无可改签车次");
        }

        // 改签后的车次验证
        if ($this->train) {
            $limit_48hour = 48 * 3600;
            // 验证原订单距发车时间
            $diffSeconds = Carbon::parse($order_train_info->getTrainDate())->diffInSeconds(Carbon::now());
            // 如果小于48小时
            if ($diffSeconds < $limit_48hour) {
                //1 不可修改目的地
                if ($order_train_info->getToCode() != $this->train->getToCode()) {
                    $this->throwOtherErrorMsg("距发车仅剩48小时，不可修改目的地");
                }
            }
        }
    }

    /**
     * @throws Exception
     */
    private function validatePassengers(): void
    {
        if (empty($this->passengers)) {
            return;
        }
        $order_passengers = $this->order_info->getPassengers();
        $change_count     = count($this->passengers);
        $query_count      = 0;
        /**
         * @var TrainOrderPassenger $order_passenger
         */
        foreach ($order_passengers as $order_passenger) {
            $query = collect($this->passengers)
                ->where('passenger_id', $order_passenger->getPassengerId())
                ->firstWhere('sequence', $order_passenger->getSequence());
            if (!$query) {
                continue;
            }
            $query_count++;
            // 验证传入乘客状态
            if (!$order_passenger->canChange()) {
                $state_desc = TripOrderState::getPassengerOrderStateDesc($order_passenger->getOrderState());
                $this->throwOtherErrorMsg("乘客{$order_passenger->getTrueName()}状态为{$state_desc}，无法改签");
            }
        }

        // 先验证 改签的乘客是否 在原订单内
        if ($query_count != $change_count) {
            $this->throwOtherErrorMsg("乘客数据与原订单乘客数据不符");
        }
    }
}